import {Component, ElementRef, EmbeddedViewRef, EventEmitter, HostListener, Injector, Input, OnInit, Output, QueryList, Renderer2, TemplateRef, ViewChild, ViewChildren, ViewEncapsulation} from '@angular/core';
import {CellComponent} from "./cell/cell.component";
import {AppComponent} from "../../../../app.component";
import {isInclude} from "../../../../support/element";
import {slice} from "../../../../support/slice";
import {Field} from "../../field/field.model";
import {Cell, CellType} from "./form.model";

@Component({
  selector: 'ss-platform-dynamic-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss'],
  host: {class: "ss-platform-dynamic-form-wraper"},
  encapsulation: ViewEncapsulation.None
})
export class FormComponent implements OnInit {

  private element: HTMLElement;
  private isStartedDrop: boolean = false;
  private isActiveDrop: boolean = false;
  private dropCellComponent: CellComponent;
  private dropRowElement: HTMLElement;
  private dropCellElement: HTMLElement;
  private dragShadowViewRef: EmbeddedViewRef<any>;
  private dragShadowElement: HTMLElement;
  // 拖拽时开始的坐标
  private startedDragY: number = 0;
  private startedDragX: number = 0;

  @Input("ss-layouts")
  layouts: Array<Array<any>> = [];
  @Input("ss-fields")
  fields: Array<Field> = [];
  // 自定义
  cells: Array<Cell> = [];
  cellsHash: any = {};

  @ViewChild("dragShadowTemplateRef")
  dragShadowTemplateRef: TemplateRef<any>;

  @ViewChildren(CellComponent)
  cellComponents: QueryList<CellComponent>;

  @Output("onSelectCell")
  onSelectCell: EventEmitter<any> = new EventEmitter<any>();

  @Output("onDeleteCell")
  onDeleteCell: EventEmitter<any> = new EventEmitter<any>();

  constructor(element: ElementRef, private elementRef: ElementRef, private appComponent: AppComponent) {
  }

  ngOnInit(): void {
    let self = this,
      fields = self.fields,
      cells = this.cells,
      cellsHash = this.cellsHash,
      layouts = this.layouts,
      element = self.element = self.elementRef.nativeElement;
    // 初始化列
    if (!cells.length) {
      fields.forEach(field => cells.push(Cell.generateNew(CellType.data, field)));
    }
    // layouts 初始化
    if (!layouts.length) {
      fields.forEach((field, index) => {
        layouts.push([field.fieldId]);
      });
    }
    // layouts 同步
    else {
      layouts.forEach(row => {
        row.forEach(fieldId => {
          // 清理无效 fieldId
          if (!fields.find(field => field.fieldId == fieldId)) {
            row.splice(row.indexOf(fieldId), 1);
          }
        })
        // 清理无效 row
        if (!row.length) {
          layouts.splice(layouts.indexOf(row), 1);
        }
      });
      let fieldIds = layouts.reduce((cells, row) => {
        return cells.concat(row);
      }, [])
      fields.filter(field => !fieldIds.find(fieldId => fieldId == field.fieldId)).forEach(field => {
        layouts.push([field.fieldId]);
      });
    }
    self.reset();
  }

  /**
   * 重置数据
   */
  reset(): void {
    let cells = this.cells,
      cellsHash = this.cellsHash,
      fields = this.fields;
    // fieldId -> cell 映射
    cells.forEach((cell, index) => {
      cellsHash[cell.field.fieldId] = cell;
    });
    // 同步 fields
    fields.splice(0, fields.length);
    cells.filter(cell => cell.type == CellType.data).forEach(cell => fields.push(cell.field));
  }

  /**
   * 开始拖拽
   * @param $event
   */
  @HostListener("mousedown", ["$event"])
  startedDrag($event: MouseEvent): void {
    let self = this,
      {x, y} = $event;
    self.startedDragX = x;
    self.startedDragY = y;
    if (isInclude(x, y, self.element)) {
      self.cellComponents.filter(cell => cell.include(x, y)).forEach(cellComponent => {
        self.isStartedDrop = true;
        self.dropCellComponent = cellComponent;
        self.dropCellElement = cellComponent.element;
        self.dropRowElement = cellComponent.rowElement;
        self.dragShadowViewRef = self.appComponent.createEmbeddedView(self.dragShadowTemplateRef);
        self.dragShadowElement = self.dragShadowViewRef.rootNodes.find(value => value);
        self.dragShadowElement.querySelector("span").innerHTML = cellComponent.cell.field.name;
      });
    }
  }

  /**
   * 进行拖拽
   * @param $event
   */
  @HostListener("document:mousemove", ["$event"])
  activeDrop($event): void {
    let self = this,
      {x, y} = $event,
      dropRowElement = self.dropRowElement,
      dropCellElement = self.dropCellElement;
    if (self.isStartedDrop && (self.isActiveDrop || (Math.abs(x - self.startedDragX) > 5 || Math.abs(y - self.startedDragY) > 5))) {
      // 影子
      self.dragShadowElement.style.transform = "translate3d(" + (x - 112) + "px," + (y - 23) + "px, 0px)";
      dropCellElement.classList.add("placeholder-active");
      self.isActiveDrop = true;
      if (isInclude(x, y, this.element)) {
        self.cellComponents.filter(cell => cell.include(x, y)).forEach(cellComponent => {
          let activeRowElement = cellComponent.rowElement;
          let rect = activeRowElement.getBoundingClientRect(),
            isBefore = y > rect.top && y < rect.top + 8,
            isInner = y > rect.top + 8 && y < rect.top + rect.height - 8,
            isAfter = y > rect.top + rect.height - 8 && y < rect.top + rect.height;
          // 前置插入、后置插入
          if (isBefore || isAfter) {
            if (dropRowElement.children.length == 1) {
              if (!dropRowElement.contains(dropCellElement)) {
                dropRowElement.append(dropCellElement);
              }
              // this.logger.debug(isBefore ? "前置插入 1" : "后置插入 1", this.dropRow, this.dropCell)
            } else {
              if (!dropRowElement.classList.contains("placeholder")) {
                dropCellElement.remove();
                dropRowElement = dropRowElement.cloneNode(true) as HTMLElement;
                dropRowElement.classList.add("placeholder");
                dropRowElement.innerHTML = "";
                dropRowElement.remove();
                // this.logger.debug(isBefore ? "前置插入 2" : "后置插入 2")
              } else {
                // this.logger.debug(isBefore ? "前置插入 3" : "后置插入 3")
              }
              dropRowElement.append(dropCellElement);
            }
            // 插入
            if (isBefore) {
              activeRowElement.before(dropRowElement);
            } else {
              activeRowElement.after(dropRowElement);
            }
          }
          // 内置插入
          else if (isInner) {
            // 插入
            if (!activeRowElement.contains(dropCellElement)) {
              activeRowElement.insertBefore(dropCellElement, activeRowElement.children.item(0));
              // this.logger.debug("内置插入")
            }
            // 交换位置
            let dropCellRect = dropCellElement.getBoundingClientRect(),
              isSwapLeft = x < dropCellRect.x,
              isSwapRight = x > dropCellRect.x + dropCellRect.width;
            // 拖拽到左侧
            if (isSwapLeft) {
              dropCellElement.after(dropCellElement.previousElementSibling);
              // this.logger.debug("内置插入 isSwapLeft")
            }
            // 拖拽到右侧
            else if (isSwapRight) {
              dropCellElement.before(dropCellElement.nextSibling);
              // this.logger.debug("内置插入 isSwapRight")
            }
            // 已存在
            else {
              // this.logger.debug("内置插入 exists")
            }
          }
        });
      }
    }
  }

  /**
   * 结束拖拽
   */
  @HostListener("document:mouseup")
  endDrop(): void {
    let self = this,
      element = self.element,
      layouts = self.layouts,
      dropRowElement = self.dropRowElement;
    // 销毁影子
    if (self.isStartedDrop) {
      self.dragShadowViewRef.destroy();
    }
    // 收集布局信息
    if (self.isActiveDrop) {
      // 同步 layouts
      layouts.splice(0, layouts.length);
      element.querySelectorAll(".ss-platform-dynamic-form-row").forEach(row => {
        if (row.children.length) {
          layouts.push(slice(row.children).map((cell: HTMLElement) => {
            return cell.getAttribute("id");
          }));
        }
      });
      if (dropRowElement) {
        dropRowElement.remove();
      }
    }
    self.isStartedDrop = self.isActiveDrop = false;
  }


  /**
   * 复制字段
   */
  copyCell(component: CellComponent): void {
    let self = this, cells = self.cells,
      layouts = self.layouts,
      newCell = Cell.copy(component.cell);
    cells.splice(cells.indexOf(component.cell) + 1, 0, newCell);
    layouts.splice(layouts.indexOf(component.row) + 1, 0, [newCell.field.fieldId]);
    self.reset();
  }

  /**
   * 删除字段
   */
  deleteCell(component: CellComponent): void {
    let self = this,
      cells = self.cells,
      layouts = self.layouts;
    cells.splice(cells.indexOf(component.cell), 1);
    component.row.splice(component.row.indexOf(component.cell.field.fieldId), 1);
    component.row.length == 0 && layouts.splice(layouts.indexOf(component.row), 1);
    self.reset();
    self.onDeleteCell.emit(component);

  }

}
